package org.ioriframework.boot.job.trigger;

import org.ioriframework.boot.job.task.RestJobTask;
import org.ioriframework.boot.job.task.RestStatefulJobTask;
import org.ioriframework.boot.job.vo.JobVO;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;

/**
 * 定时任务触发器
 * 
 * @author iori
 *
 */
@Component
public class JobTrigger {
	
	private static Logger log = LoggerFactory.getLogger(JobTrigger.class);
	
	public static final String JOB_TYPE_REST = "REST";
	public static final String Y = "Y";

	@Autowired
	@Qualifier("schedulerFactory")
	private SchedulerFactoryBean schedulerFactory;
	
	/**
	 * 触发生成定时任务
	 * @param jobVO
	 * @throws SchedulerException
	 */
	public void scheduleJob(JobVO jobVO) throws SchedulerException {
		Scheduler scheduler = schedulerFactory.getScheduler();
		TriggerKey triggerKey = TriggerKey.triggerKey(jobVO.getJobName(),
				jobVO.getGroupName());
		CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
		// 新增任务
		if (trigger == null) {
			JobDetail jobDetail = JobBuilder.newJob(findJobClass(jobVO))
					.withIdentity(jobVO.getJobName(),
							jobVO.getGroupName()).build();
			jobDetail.getJobDataMap().put("jobVO", jobVO);
			// 表达式调度构建器
			CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(jobVO.getCron());
			// 按新的表达式构建一个新的trigger
			trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey)
					.withSchedule(scheduleBuilder).build();
			scheduler.scheduleJob(jobDetail, trigger);
		}
	}
	
	/**
	 * 根据任务类型获取相应的处理类
	 * @param jobVO
	 * @return
	 */
	private Class<? extends Job> findJobClass(JobVO jobVO) {
		String jobType = jobVO.getJobType();
		String statefulFlag = jobVO.getStatefulFlag();
		if (JOB_TYPE_REST.equals(jobType) && Y.equals(statefulFlag)) {
			return RestStatefulJobTask.class;
		}
		return RestJobTask.class;
	}
	
	/**
	 * 更新定时任务的执行频率(cron表达式)
	 * @param jobVO
	 * @throws SchedulerException
	 */
	public void rescheduleJob(JobVO jobVO) throws SchedulerException {
		Scheduler scheduler = schedulerFactory.getScheduler();
		TriggerKey triggerKey = TriggerKey.triggerKey(jobVO.getJobName(),
				jobVO.getGroupName());
		// 任务不存在，生成任务
		if (!scheduler.checkExists(triggerKey)) {
			log.warn("Job[{}] not found.", triggerKey.toString());
			scheduleJob(jobVO);
		} else {
			// 任务已存在，重新设置
			CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
			// 表达式调度构建器
			CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(jobVO.getCron());
			// 按新的cronExpression表达式重新构建trigger
			trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
					.withSchedule(scheduleBuilder).build();
			// 按新的trigger重新设置job执行
			scheduler.rescheduleJob(triggerKey, trigger);
		}
	}
	
	/**
	 * 暂停任务
	 * @param jobVO
	 * @throws SchedulerException
	 */
	public void pauseJob(JobVO jobVO) throws SchedulerException {
		Scheduler scheduler = schedulerFactory.getScheduler();
		JobKey jobKey = JobKey.jobKey(jobVO.getJobName(),
				jobVO.getGroupName());
		// 任务不存在，抛出异常
		if (!scheduler.checkExists(jobKey)) {
			throw new SchedulerException("Job[" + jobKey.toString() + "] not found.");
		}
		scheduler.pauseJob(jobKey);
	}
	
	/**
	 * 恢复任务
	 * @param jobVO
	 * @throws SchedulerException
	 */
	public void resumeJob(JobVO jobVO) throws SchedulerException {
		Scheduler scheduler = schedulerFactory.getScheduler();
		JobKey jobKey = JobKey.jobKey(jobVO.getJobName(),
				jobVO.getGroupName());
		// 任务不存在，生成任务
		if (!scheduler.checkExists(jobKey)) {
			log.warn("Job[{}] not found.", jobKey.toString());
			scheduleJob(jobVO);
		} else {
			scheduler.resumeJob(jobKey);
		}
	}
	
	/**
	 * 删除任务
	 * @param jobVO
	 * @throws SchedulerException
	 */
	public void deleteJob(JobVO jobVO) throws SchedulerException {
		Scheduler scheduler = schedulerFactory.getScheduler();
		JobKey jobKey = JobKey.jobKey(jobVO.getJobName(),
				jobVO.getGroupName());
		// 任务不存在，打印异常日志
		if (!scheduler.checkExists(jobKey)) {
			log.warn("Job[{}] not found.", jobKey.toString());
		} else {
			scheduler.deleteJob(jobKey);
		}
	}
	
	/**
	 * 立即运行任务
	 * @param jobVO
	 * @throws SchedulerException
	 */
	public void triggerJob(JobVO jobVO) throws SchedulerException {
		Scheduler scheduler = schedulerFactory.getScheduler();
		JobKey jobKey = JobKey.jobKey(jobVO.getJobName(),
				jobVO.getGroupName());
		// 任务不存在，抛出异常
		if (!scheduler.checkExists(jobKey)) {
			throw new SchedulerException("Job[" + jobKey.toString() + "] not found.");
		}
		scheduler.triggerJob(jobKey);
	}
	
	/**
	 * 检查任务是否存在
	 * @param jobVO
	 * @return
	 */
	public boolean checkExists(JobVO jobVO) {
		Scheduler scheduler = schedulerFactory.getScheduler();
		JobKey jobKey = JobKey.jobKey(jobVO.getJobName(),
				jobVO.getGroupName());
		try {
			// 任务不存在，返回false
			if (!scheduler.checkExists(jobKey)) {
				log.debug("Job[{}] not found.", jobKey.toString());
				return false;
			}
		} catch (SchedulerException e) {
			log.warn("Job[{}] checkExists error, {}.", jobKey.toString(), e.getMessage());
			// 异常返回false,代表任务不存在
			return false;
		}
		// 任务不存在，返回true
		return true;
	}
}
